#!/usr/bin/env python
# encoding: utf-8
'''
Comm.MqHandler -- MQ handler

Comm.MqHandler is a description

It defines classes_and_methods

@author:     Anson Chan

@copyright:  2016 Xerland Co. Ltd. All rights reserved.

@contact:    anson_chan@xerland.com
@deffield    updated: Updated
'''
import paho.mqtt.client as mqtt
import traceback
import json
import Queue
from Utils.JsonHelper import toJson, fromJson
from Utils.SysConstants import SERVERAPI_CONFIGSERVICE, LOGGER,\
    TPLUS_POLLING_DEFAULT_INTERVAL
from Adb.MachModel import MachModel
import threading
from Utils.TopicFormater import TopicFormater

class MqHandler():
    '''
    classdocs
    '''


    def __init__(self):
        '''
        Constructor
        '''
        
        self.mHostname = TopicFormater.getHostName()    #SERVERAPI_CONFIGSERVICE.getValue("mq_hostname")
        self.mPort = TopicFormater.getHostPort() #int(SERVERAPI_CONFIGSERVICE.getValue("mq_port"))
#        self.mPowerSubUpdate = SERVERAPI_CONFIGSERVICE.getValue("mq_power_subscription_update")
#        self.mPowerSubRequest = SERVERAPI_CONFIGSERVICE.getValue("mq_power_subscription_request")
#        self.mRtdSubUpdate = SERVERAPI_CONFIGSERVICE.getValue("mq_rtd_subscription_update")
#        self.mRtdSubRequest = SERVERAPI_CONFIGSERVICE.getValue("mq_rtd_subscription_request")
        self.mSubBase = TopicFormater.getSubBaseWildcard() #SERVERAPI_CONFIGSERVICE.getValue("mq_subscription_base")
        self.mSubBaseTrim = self.mSubBase.replace('#','')
        
        self.mMqttc = mqtt.Client(TopicFormater.getClientId())#(SERVERAPI_CONFIGSERVICE.getValue("mq_client_id"))
#        self.mMqttc.message_callback_add(self.mPowerSubRequest, self.onPowerSubRequest)
#        self.mMqttc.message_callback_add(self.mRtdSubRequest, self.onRtdSubRequest)
        self.mMqttc.on_message = self.on_message
        self.mMqttc.on_connect = self.on_connect
        self.mMqttc.on_publish = self.on_publish
        self.mMqttc.on_subscribe = self.on_subscribe
        self.mMqttc.on_log = self.on_log
        self.setWill()
        self.mUpStreamQ = None
        self.mDownStreamQ = None
        self.ifStop = False
        self.mUpStreamThread = threading.Thread(target=self.upStreamHandler)
                
#        self.mTpSched = TpScheduler()
#        self.mTpSched.setPowerMonitorCb(self.doPowerMonitorCb)
#        self.mTpSched.setRtdMonitorCb(self.doRtdMonitorCb)
        
    def setUpStreamQ(self, q):
        self.mUpStreamQ = q
        
    def setDownStreamQ(self, q):
        self.mDownStreamQ = q        

    def on_connect(self, mqttc, obj, flags, rc):
        print("rc: "+str(rc))

    def on_message(self, mqttc, obj, msg):
        print("mqttc._client_id is ",mqttc._client_id)
        print(msg.topic+" "+str(msg.qos)+" "+str(msg.payload))
        machId = -1
        beginTime = 0.0
        endTime = 0.0
        if msg.payload:
            try:
                print "do json"
                payloadModel = json.loads(msg.payload, object_hook = fromJson)
                if isinstance(payloadModel, MachModel) or payloadModel == []:
                    print "do put"
                    self.mDownStreamQ.put((msg.topic,payloadModel))
            except:
                traceback.print_exc()
                LOGGER.error("Json Parsing failed!")          

    def on_publish(self, mqttc, obj, mid):
        print("mid: "+str(mid))

    def on_subscribe(self, mqttc, obj, mid, granted_qos):
        print("Subscribed: "+str(mid)+" "+str(granted_qos))

    def on_log(self, mqttc, obj, level, string):
        print(string)
        
    def setWill(self, topic=None, will=None):
        if not topic:
            topic = self.mSubBaseTrim
        if not will:
            will = "{404:\"Something Wrong! Ciao.\"}"
        self.mMqttc.will_set(topic, will, 2)
    
#    def onPowerSubRequest(self, mosq, obj, msg):
#        # Todo: parsing msg to get machId
#        machId = -1
#        if msg.payload:
#            try:
#                print msg.payload
#                payloadModel = json.loads(msg.payload, object_hook = fromJson)
#                print(payloadModel)
#                if payloadModel and hasattr(payloadModel,"mMachID"):
#                    print('do addTaskNow')
#                    machId = payloadModel.mMachID
#                    self.mTpSched.addTaskNow(self.mTpSched.getPowerState,(machId, self.doPowerMonitorCb))
#            except:
#                traceback.print_exc()
#                LOGGER.error("Json Parsing failed!")
#    
#    def onRtdSubRequest(self, mosq, obj, msg):
#        machId = -1
#        beginTime = 0.0
#        endTime = 0.0
#        if msg.payload:
#            try:
#                payloadModel = json.loads(msg.payload, object_hook = fromJson)
#                if payloadModel \
#                and hasattr(payloadModel,"mMachID") \
#                and hasattr(payloadModel,"mPowerOnTime") \
#                and hasattr(payloadModel,"mPowerOffTime"):
#                    machId = payloadModel.mMachID
#                    beginTime = payloadModel.mPowerOnTime
#                    endTime = payloadModel.mPowerOffTime
#                    self.mTpSched.addTaskNow(self.mTpSched.,(machId, beginTime, endTime, self.doRtdMonitorCb))
#            except:
#                traceback.print_exc()
#                LOGGER.error("Json Parsing failed!")        
        
#    def doPowerMonitorCb(self, powerStateList):        
#        self.mMqttc.publish(self.mPowerSubUpdate, json.dumps(powerStateList, default=toJson), qos=2)
#        
#    def doRtdMonitorCb(self, rtdUpdateList):
#        self.mMqttc.publish(self.mRtdSubUpdate, json.dumps(rtdUpdateList, default=toJson), qos=2)
#         
#    def run(self):
#        self.mTpSched.start()
#        self.mMqttc.connect(self.mHostname, self.mPort)
#        self.mMqttc.subscribe(self.mPowerSubRequest, 0)
#        self.mMqttc.subscribe(self.mRtdSubRequest, 0)
#        self.mMqttc.loop_forever()
    def upStreamHandler(self):
        while not self.ifStop:
            try:
                msg = self.mUpStreamQ.get(timeout=TPLUS_POLLING_DEFAULT_INTERVAL)
                if msg:
                    topic,modelList = msg
                    if topic and modelList:
                        try:
                            payload = json.dumps(modelList, default=toJson)
                            if "@" in topic:
#                                topic = topic.split("@")[1] + "@" + topic.split("@")[0]
#                                topic = topic.replace("request","response")
                                topic = TopicFormater.reverseSubNPub(topic)
                            self.mMqttc.publish(topic, payload, 2)
                        except:
                            traceback.print_exc()
            except Queue.Empty:
                continue
            except Exception,e:
                traceback.print_exc()       
        
    def start(self):
        self.mMqttc.connect(self.mHostname, self.mPort)
#        self.mMqttc.subscribe(self.mPowerSubRequest, 0)
#        self.mMqttc.subscribe(self.mRtdSubRequest, 0)
        self.mMqttc.subscribe(self.mSubBase, 0)
        self.mMqttc.loop_start()
        self.mUpStreamThread.start()
                
    def stop(self):
        self.ifStop = True
#        self.mTpSched.stopAll()
        self.mMqttc.loop_stop()
        self.mMqttc.disconnect()      
        self.mUpStreamThread.join()
        
if __name__ == '__main__':
    from Adb.PowerMonitor import PowerMonitor
    from Adb.RtdMonitor import RtdMonitor
    from TpScheduler import TpScheduler

    upStreamQ = Queue.Queue()
    downStreamQ = Queue.Queue()
    mq = MqHandler()
    mq.setUpStreamQ(upStreamQ)
    mq.setDownStreamQ(downStreamQ)
    mq.start()
    print('voila')    
    mTpSched = TpScheduler()
    mTpSched.setUpStreamQ(upStreamQ)
    mTpSched.setDownStreamQ(downStreamQ)
    powerMonitor = PowerMonitor()
    rtdMonitor = RtdMonitor()
    mTpSched.subTask(TopicFormater.getSubSelfPeerX("/powerstate"), powerMonitor.getMachPowerState)#SERVERAPI_CONFIGSERVICE.getValue("mq_power_subscription_request")
    mTpSched.subTask(TopicFormater.getSubSelfPeerX("/rtd"), rtdMonitor.getHistory)   #SERVERAPI_CONFIGSERVICE.getValue("mq_rtd_subscription_request")
    mTpSched.subTask(TopicFormater.getSubSelfPeerX("/rtdpage"), rtdMonitor.getHistoryPage)
    mTpSched.pubTask(6, TopicFormater.getPubSelf("/powerstate/update"), powerMonitor.getMachPowerState)   #SERVERAPI_CONFIGSERVICE.getValue("mq_power_subscription_update")
    mTpSched.pubTask(6, TopicFormater.getPubSelf("/rtd/update"), rtdMonitor.getUpdate)    #SERVERAPI_CONFIGSERVICE.getValue("mq_rtd_subscription_update")

    mTpSched.doSchedule()
    